<template>
	<slot>
		<el-button type="primary" icon="ele-Upload" class="!mr-[15px]" @click="open">导出</el-button>
	</slot>
	<el-dialog ref="dialogRef" title="导出" v-model="showDialog" width="500px" @opened="initDialog">
		<div>
			<el-form ref="formRef" :model="formData" label-width="120px" :rules="formRules" class="export-form">
				<el-form-item label="文件名称：" prop="file_name" required>
					<el-input v-model="formData.file_name" placeholder="请输入导出文件名称"></el-input>
				</el-form-item>
				<el-form-item label="文件类型：" prop="file_suffix" required>
					<el-select class="w-[120px]" v-model="formData.file_suffix" placeholder="请选择文件类型">
						<el-option v-for="item in fileTypes" :key="item" :label="'*.' + item" :value="item" />
					</el-select>
				</el-form-item>
				<el-form-item label="数据量：">
					预计导出 {{ exportData.page_total }} 条数据， 共 {{ exportData.page_sum }} 页，每页 {{ exportData.page_limit }} 条数据
				</el-form-item>
				<el-form-item v-if="!formData.is_async" label="导出限制："> 每次导出最大允许 {{ exportData.max_number }} 条数据 </el-form-item>
				<el-form-item label="导出形式：" prop="is_async" required>
					<el-radio-group v-model="formData.is_async">
						<el-radio :label="0">同步</el-radio>
						<el-radio :label="1">异步</el-radio>
					</el-radio-group>
				</el-form-item>
				<el-form-item prop="is_page" label="导出范围：" required>
					<el-radio-group v-model="formData.is_page">
						<el-radio :label="0">全部导出</el-radio>
						<el-radio :label="1">分页导出</el-radio>
					</el-radio-group>
				</el-form-item>
				<el-form-item label="分页范围：" v-if="formData.is_page == 1">
					<div class="flex w-[100px]">
						<el-form-item prop="page_start" class="!mr-[0px]">
							<el-input-number v-model.number="formData.page_start" controls-position="right" />
						</el-form-item>
						<span class="flex-none ml-2 mr-2">至</span>
						<el-form-item prop="page_end">
							<el-input-number v-model.number="formData.page_end" controls-position="right" />
						</el-form-item>
					</div>
				</el-form-item>
			</el-form>
		</div>
		<template #footer>
			<span class="dialog-footer">
				<el-button @click="showDialog = false">关闭</el-button>
				<el-button type="primary" :loading="btnLoading" @click="confirm">确认导出</el-button>
			</span>
		</template>
	</el-dialog>

	<!-- 文件下载进度条 -->
	<el-dialog
		title="正在导出，请等待..."
		v-model="progressData.show"
		:close-on-click-modal="false"
		:close-on-press-escape="false"
		:show-close="false"
		width="340px"
	>
		<div style="text-align: center">
			<el-progress :percentage="progressData.percentage" type="circle"></el-progress>
		</div>
	</el-dialog>
</template>
<script lang="ts" setup>
import { ref, reactive, shallowRef } from 'vue';
import type { FormInstance } from 'element-plus';
import { ElLoading } from 'element-plus';
import { downloadExport, downloadExportProgress } from '/@/api/download';
import type { LoadingInstance } from 'element-plus/es/components/loading/src/loading';
import { messageError, messageSuccess } from '/@/utils/message';

const props = defineProps({
	// 接口参数
	params: {
		type: Object,
		default: () => ({}),
	},
	// 每页条数
	pageSize: {
		type: Number,
		default: 1000,
	},
	// 导出文件类型
	fileTypes: {
		type: Array,
		default: () => ['xlsx', 'xls'],
	},
	// 方法
	fetchFun: {
		type: Function,
		required: true,
	},
	// 是否导出预览
	isPreview: {
		type: Boolean,
		default: true,
	},
});

const formRef = shallowRef<FormInstance>();

const dialogRef = ref(null);

const formData = reactive({
	is_async: 0,
	is_page: 0,
	page_start: 1,
	page_end: 200,
	file_name: '',
	file_suffix: '',
});

const showDialog = ref(false);

const formRules = {
	file_name: [{ required: true, message: '请输入文件名称' }],
	page_start: [
		{ required: true, message: '请输入起始页码' },
		{ type: 'number', message: '页码必须是整数' },
		{
			validator: (rule: any, value: any, callback: any) => {
				if (value <= 0) return callback(new Error('页码必须大于0'));
				callback();
			},
		},
	],
	page_end: [
		{ required: true, message: '请输入结束页码' },
		{ type: 'number', message: '页码必须是整数' },
		{
			validator: (rule: any, value: any, callback: any) => {
				if (value <= 0) return callback(new Error('页码必须大于0'));
				callback();
			},
		},
	],
};

const exportData = reactive({
	page_total: 0,
	page_num: 0,
	page_sum: 0,
	page_limit: 0,
	max_number: 0,
});

const btnLoading = ref(false);

const progressTimer = ref(null);

const progressData = reactive({
	show: false,
	percentage: 0,
});

let loadingInstance: LoadingInstance;

let loadingDownloadInstance: LoadingInstance;

const initDialog = () => {
	if (props.isPreview) {
		loadingInstance = ElLoading.service({
			target: dialogRef.value.dialogRef,
			text: '加载中...',
			lock: false,
			background: 'rgba(255, 255, 255, 0.4)',
		});
		getData();
	}
};

const emit = defineEmits(['confirm']);

const open = () => {
	// 重置数据
	formData.is_async = 0;
	formData.is_page = 0;
	formData.page_start = 1;
	formData.page_end = 200;
	progressData.percentage = 0;

	if (props.isPreview) {
		showDialog.value = true;
	} else {
		confirm();
	}
};

const getData = async () => {
	let res = await props.fetchFun({
		...props.params,
		export_type: 1,
		page_limit: props.pageSize,
		is_page: 0,
		is_async: 0,
	});

	loadingInstance?.close();
	Object.assign(exportData, res);
	formData.file_name = res.export_title;
	formData.file_suffix = res.export_suffix;
	formData.page_end = res.page_sum;
};

const confirm = async () => {
	await formRef.value?.validate();
	if(exportData.page_total > exportData.max_number && (formData.page_end - formData.page_start + 1) * 1000 > exportData.max_number && !formData.is_async) {
		messageError(`导出数据量过大，建议导出范围在${exportData.max_number}条以内`);
		return false;
	}
	if(btnLoading.value) return false;
	btnLoading.value = true;
	props
		.fetchFun({
			...props.params,
			...formData,
			export_type: 2,
			page_limit: props.pageSize,
		})
		.then((res) => {
			btnLoading.value = false;
			loadingInstance = ElLoading.service({
				target: dialogRef.value.dialogRef,
				text: '正在导出中...',
				lock: false,
				background: 'rgba(255, 255, 255, 0.4)',
			});

			// 异步导出步骤：1-加入队列(1-2s) 2-查询数据(分页查询) 3-添加excel数据(2-3s) 4-导出完成下载文件(1-2s)
			if (formData.is_async) {
				progressData.show = true;
				// 每两秒执行一次，查询进度
				progressTimer.value = setInterval(() => {
					downloadExportProgress({ file_identifier: res.file_identifier })
						.then((progress_res) => {
							if(progress_res.step < 3) {
								progressData.percentage = progress_res.step * 25;
							} else if (progress_res.step == 3) {
								progressData.percentage = 50 + Math.floor(progress_res.progress/2.5);
							} else if (progress_res.step == 4) {
								progressData.percentage = 100;
							}
							// 导出完毕删除定时器
							if (progress_res.progress == 100 && progress_res.step == 4) {
								closeTime();
								setTimeout(() => {
									if (!loadingDownloadInstance && !progress_res.file_key) {
										progressData.show = false;
										loadingDownloadInstance = ElLoading.service({
											target: dialogRef.value.dialogRef,
											text: '下载文件中...',
											lock: false,
											background: 'rgba(255, 255, 255, 0.4)',
										});
									}

									if (progress_res.file_key) {
										messageSuccess('导出完成');
										download(progress_res.file_key, progress_res.name);
									}
								}, 500);
							}
						})
						.catch(() => {
							closeTime();
						});
				}, 2000);
			} else {
				download(res.file_key, res.file_name);
			}
			loadingInstance?.close();
			showDialog.value = false;
			emit('confirm', res);
		})
		.catch(() => {
			btnLoading.value = false;
		});
};

const download = (file_key: string, file_name: string) => {
	downloadExport({ file_key: file_key, file_name: file_name });
};

const closeTime = () => {
	progressData.show = false;
	window.clearInterval(progressTimer.value);
	progressTimer.value = null;
	loadingDownloadInstance?.close();
};

defineExpose({
	open,
});
</script>
<style lang="scss" scoped>
.export-form .el-form-item {
	margin-bottom: 15px;
}
</style>
